#include "BPlusPlus.h"
#include "File.h"
#include "Page.h"
#include "ImposibleWriteFileException.h"
#include "ImposibleReadFileException.h"
#include "ImposibleOpenFileException.h"
#include "ImposibleCloseFileException.h"
#include "NotExistNameException.h"
#include "TransactionLog.h"

#ifndef ZERO
	#define ZERO 0
#endif

#ifndef UNO
	#define UNO 1
#endif

#ifndef DOS
	#define DOS 2
#endif

#ifndef MENOS_UNO
	#define MENOS_UNO -1
#endif

#ifndef FIRST_ROOT
	#define FIRST_ROOT 128
#endif

#ifndef SIZE_HEADER
	#define SIZE_HEADER 128
#endif

#ifndef MAX_SIZE_PAGE
	#define MAX_SIZE_PAGE 4096
#endif

#define OPERADOR_NULO 0
#define OPERADOR_MAYOR 1
#define OPERADOR_MAYOR_IGUAL 2
#define OPERADOR_IGUAL 3
#define OPERADOR_MENOR 4
#define OPERADOR_MENOR_IGUAL 5
#define OPERADOR_DISTINTO 6


BPlusPlus::BPlusPlus()
	:filename(""),
	level(ZERO),
	root(FIRST_ROOT),
	currentPage(FIRST_ROOT),
	currentKey(ZERO),
	stopPage(FIRST_ROOT),
	stopKey(ZERO),
	currentOperator(OPERADOR_NULO)
{
}

BPlusPlus::~BPlusPlus()
{
	filename.clear();
	level = ZERO;
	root = ZERO;
	currentPage = ZERO;
	currentKey = ZERO;
	stopPage = ZERO;
	stopKey = ZERO;
	currentOperator = OPERADOR_NULO;
	this->clearStack();
	
}

int BPlusPlus::create(std::string name)
{
	char header[SIZE_HEADER] = {ZERO};
	char* current = header;
	char* data = NULL;
	unsigned int size = ZERO;
	File* file = NULL;
	
	//TransactionLog::Create(name);

	if(level != ZERO || root != FIRST_ROOT || currentPage != FIRST_ROOT || currentKey != ZERO)
		return B_ERROR;

	try
	{
		// Escribo el header del arbol
		filename = name;

		if(filename == "")
		{
			throw NotExistNameException ();
		}
		file = new File();
		
		if(file->exists((char*)filename.c_str()))
		{
			if(file != NULL)
				delete file;
			return B_EXISTE;
		}
	
		memcpy(current, (char*)&level, sizeof(int));
		current += sizeof(int);
		memcpy(current, (char*)&root, sizeof(int));
		current += sizeof(int);
		memcpy(current, (char*)&currentPage, sizeof(int));
		current += sizeof(int);
		memcpy(current, (char*)&currentKey, sizeof(unsigned int));
		current += sizeof(unsigned int);
		memcpy(current, (char*)&stopPage, sizeof(int));
		current += sizeof(int);
		memcpy(current, (char*)&stopKey, sizeof(unsigned int));
		current += sizeof(unsigned int);
		memcpy(current, (char*)&currentOperator, sizeof(int));
		current += sizeof(int);

		data = new char[MAX_SIZE_PAGE];
		initialKeyCondition.getKey(data, size);

		memcpy(current, (char*)&size, sizeof(unsigned int));
		current += sizeof(unsigned int);
		if( size > ZERO)
			memcpy(current, data, size);
		current += size;

		delete []data;

		//std::cout << (int)(current - header) << std::endl;	
		
		
		if((file->open(filename.c_str()))==F_ERROR)
		{
			if(file != NULL)
				delete file;
			throw ImposibleOpenFileException ();
		}

		if((file->write(header, SIZE_HEADER))==F_ERROR )
		{	
			if(file != NULL)
				delete file;
			throw ImposibleWriteFileException ();
		}

		if(file->close() == F_ERROR)
		{
			if(file != NULL)
				delete file;
			throw ImposibleCloseFileException ();
		}

		delete file;

		// Escribo la raiz sin claves
		SequenceSet* sequence = new SequenceSet();
		sequence->setFilename(filename);
		sequence->setOffset(FIRST_ROOT);
		sequence->save();
		delete sequence;

		return B_OK;
	}
	catch ( NotExistNameException & ex1)
	{
		throw NotExistNameException ();
	}
	catch ( ImposibleOpenFileException & ex2)
	{
		throw ImposibleOpenFileException ();
	}
	catch ( ImposibleCloseFileException  & ex3)
	{
		throw ImposibleCloseFileException ();
	}
	catch ( ImposibleWriteFileException  & ex3)
	{
		throw ImposibleWriteFileException ();
	}
	catch ( EjerciceException & ex4)
	{
		throw EjerciceException ();
	}
	return B_ERROR;
}

int BPlusPlus::open(std::string name)
{
	char header[SIZE_HEADER] = {ZERO};
	char* current = header;
	File* file = NULL;
	char* data = NULL;
	unsigned int size = ZERO;

	try
	{
		// Escribo el header del arbol
		filename = name;

		if(filename == "")
		{	
			throw NotExistNameException ();
		}
		file = new File();

		if(!file->exists((char*)filename.c_str()))
		{
			if(file != NULL)
				delete file;
			return B_NO_EXISTE;
		}

		if((file->open(filename.c_str()))==F_ERROR)
		{	
			if(file != NULL)
				delete file;
			throw ImposibleOpenFileException ();
		}

		if((file->read(header, SIZE_HEADER))==F_ERROR )
		{	
			if(file != NULL)
				delete file;
			throw ImposibleReadFileException ();
		}
		
		if(file->close() == F_ERROR)
		{
			if(file != NULL)
				delete file;
			throw ImposibleCloseFileException ();
		}
		delete file;
	
		memcpy((char*)&level, current, sizeof(int));
		current += sizeof(int);
		memcpy((char*)&root, current, sizeof(int));
		current += sizeof(int);
		memcpy((char*)&currentPage, current, sizeof(int));
		current += sizeof(int);
		memcpy((char*)&currentKey, current, sizeof(unsigned int));
		current += sizeof(unsigned int);
		memcpy((char*)&stopPage, current, sizeof(int));
		current += sizeof(int);
		memcpy((char*)&stopKey, current, sizeof(unsigned int));
		current += sizeof(unsigned int);
		memcpy((char*)&currentOperator, current, sizeof(int));
		current += sizeof(int);

		data = new char[MAX_SIZE_PAGE];

		memcpy((char*)&size, current, sizeof(unsigned int));
		current += sizeof(unsigned int);
		memcpy(data, current, size);
		current += size;

		initialKeyCondition.setKey(data, size, ZERO);

		delete []data;
		
		return B_OK;
	}
	catch ( NotExistNameException & ex1)
	{
		throw NotExistNameException ();
	}
	catch ( ImposibleOpenFileException & ex2)
	{
		throw ImposibleOpenFileException ();
	}
	catch ( ImposibleCloseFileException  & ex3)
	{
		throw ImposibleCloseFileException ();
	}
	catch ( ImposibleReadFileException  & ex3)
	{
		throw ImposibleWriteFileException ();
	}
	catch ( EjerciceException & ex4)
	{
		throw EjerciceException ();
	}
	return B_ERROR;
}

void BPlusPlus::close()
{
	char header[SIZE_HEADER] = {ZERO};
	char* current = header;
	File* file = NULL;
	char* data = NULL;
	unsigned int size = ZERO;
	
	try
	{
		// Escribo el header del arbol actualizando el level
		if(filename == "")
		{
			throw NotExistNameException ();
		}
		file = new File();
		
		if(!file->exists((char*)filename.c_str()))
		{
			if(file != NULL)
				delete file;
			return;
		}
	
		memcpy(current, (char*)&level, sizeof(int));
		current += sizeof(int);
		memcpy(current, (char*)&root, sizeof(int));
		current += sizeof(int);
		memcpy(current, (char*)&currentPage, sizeof(int));
		current += sizeof(int);
		memcpy(current, (char*)&currentKey, sizeof(unsigned int));
		current += sizeof(unsigned int);
		memcpy(current, (char*)&stopPage, sizeof(int));
		current += sizeof(int);
		memcpy(current, (char*)&stopKey, sizeof(unsigned int));
		current += sizeof(unsigned int);
		memcpy(current, (char*)&currentOperator, sizeof(int));
		current += sizeof(int);

		data = new char[MAX_SIZE_PAGE];
		initialKeyCondition.getKey(data, size);

		memcpy(current, (char*)&size, sizeof(unsigned int));
		current += sizeof(unsigned int);
		memcpy(current, data, size);
		current += size;

		delete []data;
		
		if((file->open(filename.c_str()))==F_ERROR)
		{	
			if(file != NULL)
				delete file;
			throw ImposibleOpenFileException ();
		}

		if((file->write(header, SIZE_HEADER))==F_ERROR )
		{	
			if(file != NULL)
				delete file;
			throw ImposibleWriteFileException ();
		}

		if(file->close() == F_ERROR)
		{
			if(file != NULL)
				delete file;
			throw ImposibleCloseFileException ();
		}

		delete file;
		
	}
	catch ( NotExistNameException & ex1)
	{
		throw NotExistNameException ();
	}
	catch ( ImposibleOpenFileException & ex2)
	{
		throw ImposibleOpenFileException ();
	}
	catch ( ImposibleCloseFileException  & ex3)
	{
		throw ImposibleCloseFileException ();
	}
	catch ( ImposibleWriteFileException  & ex3)
	{
		throw ImposibleWriteFileException ();
	}
	catch ( EjerciceException & ex4)
	{
		throw EjerciceException ();
	}

	// Inicializo todos los atributos a sus valores por defecto
	filename.clear();
	level = ZERO;
	root = FIRST_ROOT;
	currentPage = FIRST_ROOT;
	currentKey = ZERO;
	stopPage = FIRST_ROOT;
	stopKey = ZERO;
	currentOperator = OPERADOR_NULO;
	this->clearStack();
}

void BPlusPlus::clearStack()
{
	while(ZERO != stackPage.size())
		stackPage.pop();
}

Page* BPlusPlus::newLoadedSequencePage(int offset)
{
	Page* node = new SequenceSet();
	node->setFilename(filename);
	node->setOffset(offset);
	node->load();
	return node;
}

Page* BPlusPlus::newLoadedIndexPage(int offset)
{
	Page* node = new IndexSet();
	node->setFilename(filename);
	node->setOffset(offset);
	node->load();
	return node;
}

void BPlusPlus::searchToStart(Key *key)
{
	unsigned int pos = ZERO, tempPos = ZERO;
	int nrrDesc = ZERO;
	Page * node = NULL;
	Key tempKey;
	int totalLevel = level - UNO;
	int count = ZERO;
	
	if(level != ZERO )
	{	// establezco la posicion donde tendria que ir
		node = this->newLoadedIndexPage(root);
		node->findFirstKey(key, pos);
		
//		std::cout << "POS: " << pos << std::endl << std::endl;
//		node->print();
		
		
		if(pos > ZERO)
		{
			tempPos = pos - 1;
			node->get(tempPos, &tempKey);
//			if( tempKey > (*key) || tempKey == (*key)) ANDRES< POR FAVOR VERIFICA ESTO.
			if( tempKey == (*key))
				pos--;
		}		
					
		((IndexSet*)node)->getNrr(pos, nrrDesc);
		stackPage.push(node->getOffset());
		delete node;
		
		// chequeo cuantos niveles de nodos indice tiene el arbol
		while( count < totalLevel )
		{
			Page* aux = this->newLoadedIndexPage(nrrDesc);
			stackPage.push(aux->getOffset());

			// chequeo si esta en la pagina
			aux->findFirstKey(key, pos);
		
//			std::cout << "POS: " << pos << std::endl << std::endl;
//			aux->print();
			
			if(pos > ZERO)
			{
				tempPos = pos - 1;
				aux->get(tempPos, &tempKey);
//				if( tempKey > (*key) || tempKey == (*key)) ANDRES VERIFICA ESTO POR FAVOR
				if(tempKey == (*key))
					pos--;
			}
			
			((IndexSet*)aux)->getNrr(pos, nrrDesc);

			count++;
			delete aux;
		}
		
		Page* son = newLoadedSequencePage(nrrDesc);		
		stackPage.push(son->getOffset());
		
//		son->print();
		
		delete son;
	}
}

void BPlusPlus::searchToAdd(Key *key)
{
	unsigned int pos = ZERO;
	int nrrDesc = ZERO;
	Page * node = NULL;
	int totalLevel = level - UNO;
	int count = ZERO;
	
	if(level != ZERO )
	{	// establezco la posicion donde tendria que ir
		node = this->newLoadedIndexPage(root);
		node->findLastKey(key, pos);		
		((IndexSet*)node)->getNrr(pos, nrrDesc);
		stackPage.push(node->getOffset());
		delete node;
		
		// chequeo cuantos niveles de nodos indice tiene el arbol
		while( count < totalLevel )
		{
			Page* aux = this->newLoadedIndexPage(nrrDesc);
			stackPage.push(aux->getOffset());

			// chequeo si esta en la pagina
			aux->findLastKey(key, pos);
			((IndexSet*)aux)->getNrr(pos, nrrDesc);

			count++;
			delete aux;
		}
		
		Page* son = newLoadedSequencePage(nrrDesc);		
		stackPage.push(son->getOffset());
		delete son;
	}
}

void BPlusPlus::newRoot(Key* keyPromoted, int nrrPromoted)
{
	IndexSet* index = new IndexSet();
	index->setFilename(filename);
	level++;
	index->setLevel(level);
	
	index->add(keyPromoted);
	index->addNrr(ZERO, nrrPromoted + MAX_SIZE_PAGE);
	index->addNrr(UNO, nrrPromoted);
	index->setOffset(FIRST_ROOT);	
	index->save();
	//index->print();
	delete index;
}

int BPlusPlus::add(char* ptr, unsigned int size, int nrr)
{
	Key toInsert, keyPromoted;
	int nrrPromoted = ZERO;
	int nrrInsert = ZERO;
	int returnCondition = ZERO;
	int nrrLeft = ZERO;
	int pos = ZERO;
	bool inserto = false;
	Page *node = NULL;
	SequenceSet* son = NULL;
	IndexSet* index = NULL;
	int retorno = B_ERROR;
	
	//TransactionLog::Write(this->filename, ptr, size, nrr);

	if( ptr != NULL && size > ZERO)
	{
		toInsert.setKey(ptr, size, nrr);
				
		if(level == ZERO)
		{
			/* si el nivel es zero entonces la raiz es un nodo terminal */
			node = this->newLoadedSequencePage(root);
						
			returnCondition = node->add(&toInsert);
			if(returnCondition == S_OK)
			{ // inserto la clave sin problemas
				node->save();
			}
			else
			{
				if(returnCondition == S_OVERFLOW)
				{// no la pudo insertar ya que la raiz esta llena por lo tanto realizo un split
					//((SequenceSet*)node)->print();
					((SequenceSet*)node)->split(&toInsert, &keyPromoted, nrrPromoted);
					node->setOffset(nrrPromoted + MAX_SIZE_PAGE);
					node->save();
					// establezco en la posicion 128 la nueva raiz
					this->newRoot(&keyPromoted, nrrPromoted);
				}

			}
			delete node;
			retorno = B_OK;
		}
		else
		{	// si el nivel no es zero , la raiz es un nodo no terminal
			this->clearStack();
			this->searchToAdd(&toInsert);
		
			son = (SequenceSet*)this->newLoadedSequencePage(stackPage.top());
			returnCondition = son->add(&toInsert);
			if(returnCondition == S_OK)
			{ // inserto la clave sin problemas
				son->save();
				retorno = B_OK;
			}
			else
			{
				if(returnCondition == S_OVERFLOW)
				{ // Aca empieza los split con la promocion hacia arriba
				
					son->split(&toInsert, &keyPromoted, nrrPromoted);
					nrrLeft = son->getOffset();
					son->save();
					// Saco al nodo hoja del stack para que quede el inmediato
					// padre en el tope
					stackPage.pop();
					inserto = false;
					while(!inserto)
					{
						index = (IndexSet*)this->newLoadedIndexPage(stackPage.top());
						pos = index->add(&keyPromoted);
						
						if(pos >= ZERO)
						{
							//index->addNrr(pos, nrrLeft);
							index->addNrr(pos + UNO, nrrPromoted);
							index->save();
							retorno = B_OK;
							inserto = true;
						}
						else
						{ // como no entra realizo un split
							toInsert = keyPromoted;
							nrrInsert = nrrPromoted;
							index->split(&toInsert, nrrInsert, &keyPromoted, nrrPromoted);
							
							if(level == index->getLevel())
							{
								// No tengo mas padres, o sea que el arbol crece
								// en un nivel, para lo cual creo una nueva raiz
								nrrLeft = nrrPromoted + MAX_SIZE_PAGE;
								index->setOffset(nrrLeft);
								index->save();

								// establezco en la posicion 128 la nueva raiz
								this->newRoot(&keyPromoted, nrrPromoted);
								
								stackPage.pop();
								stackPage.push(FIRST_ROOT);
								inserto = true;
							}
							else
							{	// como no es la raiz la escribo y saco el padre para
								// insertar la clave promocionada
								nrrLeft = index->getOffset();
								index->save();
								stackPage.pop();
							}
						}
						delete index;
					}
				}
			}
			delete son;
			this->clearStack();
			retorno = B_OK;
		}
	}	
	return retorno;
}

int BPlusPlus::update(char* ptr, unsigned int size, int newNrr)
{
	return 0;
}

int BPlusPlus::erase(char* ptr, unsigned int size, int nrr)
{
	return 0;
}

int BPlusPlus::get(char* ptr, unsigned int size)
{
	Key key;
	Page* node = NULL;
	int retorno = B_ERROR;

	if(ptr != NULL && size > ZERO)
	{
		key.setKey(ptr, size, ZERO);
	
		if(level == ZERO)
		{
			node = this->newLoadedSequencePage(this->root);

			//node->print();

			if(node->get(&key) == S_OK)
				retorno = key.getOffset();
			else
				retorno = B_NO_EXISTE;
			delete node;
		}
		else
		{
			// busco el respectivo nodo hijo
			this->clearStack();
			this->searchToStart(&key);
			
			// comparo la altura del arbol con la cantidad de elementos de la pila
			if(level != stackPage.size() )
			{ // el dato tiene que estar en una pagina hijo
				node = this->newLoadedSequencePage(stackPage.top());
	
				if(node->get(&key) == S_OK)
					retorno = key.getOffset();
				else
					retorno = B_NO_EXISTE;
				delete node;
			}
			
			this->clearStack();
		}
	}
	return retorno;
}

unsigned int BPlusPlus::getLevel()
{
	return this->level;
}

unsigned int BPlusPlus::getConditionKey(char* operador)
{
	unsigned int retorno = OPERADOR_NULO;
	unsigned int sizeOperador = ZERO;

	if(operador != NULL)
	{
		sizeOperador = strlen(operador);
		if(sizeOperador == UNO)
		{
			switch(operador[ZERO])
			{
				case '=': retorno = OPERADOR_IGUAL; break;
				case '>': retorno = OPERADOR_MAYOR; break;
				case '<': retorno = OPERADOR_MENOR; break;
			};
		}
		else
		{
			if(sizeOperador == DOS)
			{
				if(operador[ZERO] == '!' && operador[UNO] == '=')
					retorno = OPERADOR_DISTINTO;
				else
					if(operador[ZERO] == '>' && operador[UNO] == '=')
						retorno = OPERADOR_MAYOR_IGUAL;
					else
						if(operador[ZERO] == '<' && operador[UNO] == '=')
							retorno = OPERADOR_MENOR_IGUAL;
			}
		}
	}
	return retorno;
}

int BPlusPlus::getFirstSequence()
{
	int nrrDesc = ZERO;
	Page * node = NULL;
	int totalLevel = level - UNO;
	int count = ZERO;
	
	if(level != ZERO )
	{	// establezco la posicion donde tendria que ir
		node = this->newLoadedIndexPage(root);
		((IndexSet*)node)->getNrr(ZERO, nrrDesc);
		delete node;
		
		// chequeo cuantos niveles de nodos indice tiene el arbol
		while( count < totalLevel )
		{
			Page* aux = this->newLoadedIndexPage(nrrDesc);
		
			// chequeo si esta en la pagina
			((IndexSet*)aux)->getNrr(ZERO, nrrDesc);

			count++;
			delete aux;
		}
		return nrrDesc;
	}
	else
		return FIRST_ROOT;
}

int BPlusPlus::getLastSequence()
{
	int nrrDesc = ZERO;
	Page * node = NULL;
	int totalLevel = level - UNO;
	int count = ZERO;
	
	if(level != ZERO )
	{	// establezco la posicion donde tendria que ir
		node = this->newLoadedIndexPage(root);
		((IndexSet*)node)->getNrr(((IndexSet*)node)->getCount() + UNO, nrrDesc);
		delete node;
		
		// chequeo cuantos niveles de nodos indice tiene el arbol
		while( count < totalLevel )
		{
			Page* aux = this->newLoadedIndexPage(nrrDesc);
		
			// chequeo si esta en la pagina
			((IndexSet*)aux)->getNrr(((IndexSet*)aux)->getCount() + UNO, nrrDesc);

			count++;
			delete aux;
		}
		return nrrDesc;
	}
	else
		return FIRST_ROOT;
}

void BPlusPlus::getHighKey(int offset, Key *condition, Key *stop, int &posPageStop, unsigned int &posKeyStop)
{
	bool find = false;
	SequenceSet *temp = NULL;
	unsigned int i = ZERO;
	
	if(condition != NULL && stop != ZERO)
	{
		while(offset != ZERO && !find)
		{
			temp = (SequenceSet*)this->newLoadedSequencePage(offset);
			i = ZERO;
			while(i < temp->getCount() && !find)
			{
				temp->get(i, stop);
				if((*condition) < (*stop))
					find = true;
				else
					i++;
			}
			if(find)
			{
				posPageStop = temp->getOffset();
				posKeyStop = i;
			}
			else
				offset = temp->getNext();
			delete temp;
		}
		if(!find)
		{
			posPageStop = ZERO;
		}
	}
}

void BPlusPlus::getHighAndEqualKey(int offset, Key *condition, Key *stop, int &posPageStop, unsigned int &posKeyStop)
{
	bool find = false;
	SequenceSet *temp = NULL;
	unsigned int i = ZERO;
	
	if(condition != NULL && stop != ZERO)
	{
		while(offset != ZERO && !find)
		{
			temp = (SequenceSet*)this->newLoadedSequencePage(offset);
			i = ZERO;
			while(i < temp->getCount() && !find)
			{
				temp->get(i, stop);
//				condition->print();
//				stop->print();
				
				if( (*condition) < (*stop) || (*condition) == (*stop))
					find = true;
				else
					i++;
			}
			if(find)
			{
				posPageStop = temp->getOffset();
				posKeyStop = i;
			}
			else
				offset = temp->getNext();
			delete temp;
		}
		if(!find)
		{
			posPageStop = ZERO;
		}
	}
}

void BPlusPlus::start(char* operador, char* ptr, unsigned int size)
{
	SequenceSet *son = NULL;
	char emptyPtr[DOS] = {ZERO};
	int temp = ZERO;
	
	if(operador != NULL && ptr != NULL && size > ZERO)
	{
		initialKeyCondition.setKey(ptr, size, ZERO);
		finalKeyCondition.setKey(emptyPtr, UNO, ZERO);

		if(level == ZERO)
		{
			temp = FIRST_ROOT;
		}
		else
		{
			// busco el respectivo nodo hijo
			this->clearStack();
			this->searchToStart(&initialKeyCondition);
			temp = stackPage.top();
		}

		currentOperator = this->getConditionKey(operador);

		son = (SequenceSet*)this->newLoadedSequencePage(temp);
		
		switch(currentOperator)
		{
			case OPERADOR_MENOR:
			{
				// Posiciono el current en la primera clave, no hace
				// falta tomar la clave de corte porque con la
				// condicion alcanza.
				this->currentPage = this->getFirstSequence();
				this->currentKey = ZERO;
			}break;
			case OPERADOR_MENOR_IGUAL:
			{
				// Posiciono el current en la primera clave, no hace
				// falta tomar la clave de corte porque con la
				// condicion alcanza.
				this->currentPage = this->getFirstSequence();
				this->currentKey = ZERO;
			}break;
			case OPERADOR_DISTINTO:
			{
				// Posiciono el current en la primera clave.
				this->currentPage = this->getFirstSequence();
				this->currentKey = ZERO;
				// Tomo la clave mayor e igual para retomar la posicion cuando
				// se encuentre con la clave igual.
				this->getHighAndEqualKey(son->getOffset(), &initialKeyCondition, &finalKeyCondition, stopPage, stopKey);
			}break;
			case OPERADOR_MAYOR:
			{
				// Posiciono el current en la clave mayor.
				this->getHighKey(son->getOffset(), &initialKeyCondition, &finalKeyCondition, this->currentPage, this->currentKey);
				// No hace falta cortar porque corta en el EOF.
			}break;
			case OPERADOR_MAYOR_IGUAL:
			{
				// Posiciono el current en la clave mayor e igual.
				this->getHighAndEqualKey(son->getOffset(), &initialKeyCondition, &finalKeyCondition, this->currentPage, this->currentKey);
				// No hace falta cortar porque corta en el EOF.
			}break;
			case OPERADOR_IGUAL:
			{
				// Posiciono el current en la clave mayor e igual.
				this->getHighAndEqualKey(son->getOffset(), &initialKeyCondition, &finalKeyCondition, this->currentPage, this->currentKey);
				// No hace falta cortar porque corta en el EOF o cuando no se
				// Cumple la condicion.
			}break;
		};
		delete son;
		
		this->clearStack();
	}
}

bool BPlusPlus::hasNext()
{
	Key temp;
	SequenceSet* son = NULL;
	bool retorno = true;
	
	if(this->currentPage != ZERO)
	{
		son = (SequenceSet*)this->newLoadedSequencePage(this->currentPage);

		if(son->getCount() > ZERO)
		{
			// Primero chequeo que no este en el EOF
			if( this->currentKey == son->getCount())
			{
				if( son->getNext() == ZERO)
					retorno = false;
			}
			if(retorno)
			{
				switch(currentOperator)
				{
					case OPERADOR_MENOR:
					{
						// Chequeo que se cumpla la condicion de menor
						son->get(this->currentKey, &temp);
						if(temp < initialKeyCondition)
							retorno = true;
						else
							retorno = false;
					}break;
					case OPERADOR_MENOR_IGUAL:
					{
						// Chequeo que se cumpla la condicion de menor o igual
						son->get(this->currentKey, &temp);
						if(temp < initialKeyCondition || temp == initialKeyCondition)
							retorno = true;
						else
							retorno = false;
					}break;
					case OPERADOR_DISTINTO:
					{
						// Chequeo que se cumpla la condicion de desigualdad,
						// caso contrario salto a la clave mayor e igual
						son->get(this->currentKey, &temp);
						if(temp != initialKeyCondition)
							retorno = true;
						else
						{
							if(this->stopPage != ZERO)
							{
								this->currentPage = this->stopPage;
								this->currentKey = this->stopKey;
								retorno = true;
							}
							else
								retorno = false;
						}
					}break;
					case OPERADOR_MAYOR:
					{
						// No hace falta cortar porque corta en el EOF.
						retorno = true;
					}break;
					case OPERADOR_MAYOR_IGUAL:
					{
						// No hace falta cortar porque corta en el EOF.
						retorno = true;
					}break;
					case OPERADOR_IGUAL:
					{
						// Chequeo que se cumpla la condicion de igualdad
						son->get(this->currentKey, &temp);
						if(temp == initialKeyCondition)
							retorno = true;
						else
							retorno = false;
					}break;
				};
			}
		}
		else
			retorno = false;
		delete son;
	}
	return retorno;
}


void BPlusPlus::next(Key* key)
{
	int nextId = ZERO;
	SequenceSet* son = NULL;
	Key aux;
	
	if(key != NULL && this->currentPage != ZERO)
	{
		son = (SequenceSet*)this->newLoadedSequencePage(this->currentPage);

		if(son->getCount() > ZERO)
		{
			if(this->currentKey == son->getCount() - UNO )
			{ // estoy en la ultima clave del nodo , entonces levanto el que sigue
				nextId = son->getNext();
				son->get(this->currentKey, key);
				this->currentKey = ZERO;
				this->currentPage = nextId;				
			}
			else
			{ // como no estoy en la ultima posicion levanto la clave correspondiente
				son->get(this->currentKey, key);
				this->currentKey++;
			}
		}
		delete son;
	}
}


void BPlusPlus::Destroy(char *filename)
{
	remove(filename);
}

int BPlusPlus::Min()
{
	Key key;
	int retorno = ZERO;
	char data[MAX_SIZE_PAGE] = {0};
	char compare[MAX_SIZE_PAGE] = {0};
	unsigned int size = ZERO;
	SequenceSet* son = NULL;
	int offset = this->getFirstSequence();
	bool findStop = false;
	
	memset(compare, ZERO, MAX_SIZE_PAGE);
	
	while((offset != MENOS_UNO || offset != ZERO) && !findStop )
	{
		son = (SequenceSet*)this->newLoadedSequencePage(offset);
		findStop = false;
		for(unsigned int pos = ZERO; pos < son->getCount() && !findStop; pos++)
		{
			son->get(pos, &key);
			
			key.getKey(data, size);
			
			if(memcmp(data, compare, size) != ZERO)
			{
				findStop = true;
				retorno = (int)key.getOffset();
			}
		}
		if(!findStop)
		{
			offset = son->getNext();
			delete son;			
		}
	}
	
	return retorno;
}

int BPlusPlus::Max()
{
	Key key;
	SequenceSet* son = (SequenceSet*)this->newLoadedSequencePage(this->getLastSequence());
	unsigned int posMax = son->getCount();

	if(posMax > ZERO)
	{
		son->get(posMax - UNO, &key);
		delete son;
	}
	else
	{
		delete son;
		return MENOS_UNO;
	}
	
	return key.getOffset();
}






